<!-- 作者:高翔宇 时间:2024/6/2 周日 16:25 -->
<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
import {onBeforeUnmount, onMounted, reactive, ref, shallowRef, watch} from 'vue';
import {Editor, Toolbar} from '@wangeditor/editor-for-vue';
import {DomEditor, IDomEditor, IToolbarConfig} from '@wangeditor/editor';
import type {TabsPaneContext} from 'element-plus';
import {useMediaStore, useSettingStore, useUserStore} from "@/store";
import {ArticleImage, ArticleTypeEnum, SaveArticleImgReqData} from "@/api/article/type.ts";
import {useArticleStore} from "@/store/modules/article";
import {router} from "@/router";
import {Plus, RefreshRight, Warning} from '@element-plus/icons-vue'
import {saveArticleImageUrlReq} from "@/api/article/article.ts";

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef<IDomEditor>();

// 内容 HTML
// const valueHtml = ref('<p>hello</p>');

onMounted(() => {
  useArticleStore().articleInfo.tempId = generateUUID();
  console.log('tempId', useArticleStore().articleInfo.tempId);
});

const toolbarConfig: Partial<IToolbarConfig> = {
  // 自定义工具栏配置
};

// 定义插入函数类型（根据wangEditor类型定义）
type InsertFnType = (url: string, alt?: string, href?: string) => void;

// 编辑器配置
const editorConfig = {
  placeholder: '请输入内容...',
  MENU_CONF: {
    uploadImage: {
      // 自定义选择图片逻辑，仅打开对话框不立即插入
      customBrowseAndUpload(insertFn: InsertFnType) {
        centerDialogVisible.value = true;
        insertImage.value = insertFn; // 保存插入函数到响应式变量
        console.log('调起图片上传窗口~');
        getMediaList();
      }
    }
  }
};

// 定义 mode 变量，控制编辑器模式
const mode = ref('default'); // 或其他模式

// 组件销毁时，销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor) {
    editor.destroy();
  }
  useArticleStore().clearArticleInfo();
});

// 编辑器创建时回调
const handleCreated = (editor: IDomEditor) => {
  console.log('Editor instance:', editor);
  editorRef.value = editor;
  setTimeout(() => {
    const toolbar = DomEditor.getToolbar(editor);
    toolbar && console.log('Toolbar keys:', toolbar.getConfig().toolbarKeys);
    console.log('All menu keys:', editor.getAllMenuKeys());
  }, 0);
};

// 控制图片插入模态框
const centerDialogVisible = ref(false);
const insertImage = ref<InsertFnType>(); // 保存编辑器插入函数，图片上传成功后调用它
const activeName = ref('first'); // tab切换状态

// tab切换处理
const handleClick = (tab: TabsPaneContext, event: Event) => {
  console.log('Tab clicked:', tab, event);
};

// 图片上传数据存储
const imgData = ref<ArticleImage>();

// 上传成功处理（关键修改点：在此处执行插入逻辑）
const handleUploadSuccess = (response: any) => {
  console.log('handleUploadSuccess', response);
  imgData.value = response.data;

  // 校验插入函数和图片地址有效性
  if (insertImage.value && imgData.value?.imageUrl) {
    insertImage.value(
        imgData.value.imageUrl,
        imgData.value.imageName,
        imgData.value.imageUrl
    );
  }
  centerDialogVisible.value = false;
};

// 编辑器内容变化时回调
const handleChange = (editor: IDomEditor) => {
  console.log('Content changed:', editor.getHtml());
  useArticleStore().articleInfo.content = editor.getHtml();
};

const saveArticle = async (type: number) => {
  if (radio.value === 1) {
    useArticleStore().articleInfo.cover = useArticleStore().possibleCovers.selectedCover;
  } else if (radio.value === 2) {
    useArticleStore().articleInfo.cover = useArticleStore().possibleCovers.contentCover;
  } else if (radio.value === 3) {
    useArticleStore().articleInfo.cover = useArticleStore().possibleCovers.fromMaterialRepository;
  }
  if (type === 1) {
    // 保存草稿
    useArticleStore().saveDraft().then(() => {
      console.log('保存草稿成功');
      router.push('/manage/article')
      useArticleStore().clearArticleInfo()
    })
  } else if (type === 2) {
    // 提交审核
    useArticleStore().submitArticle().then(() => {
      console.log('提交审核成功');
      router.push('/manage/article')
      useArticleStore().clearArticleInfo()
    })
  }
}

// 上传错误处理
const uploadError = (err: any) => {
  console.log('uploadError', err);
  if (err.toString().includes('401')) {
    ElMessage.error('登录过期，请重新登录');
    router.push('/login');
  } else {
    ElMessage.error('上传失败');
  }
};

function generateUUID() {
  const hexDigits = "0123456789abcdef";
  const s = new Array(36);

  for (let i = 0; i < 36; i++) {
    if (i === 8 || i === 13 || i === 18 || i === 23) {
      s[i] = "-";
    } else if (i === 14) {
      s[i] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
    } else if (i === 19) {
      s[i] = hexDigits[(Math.random() * 4) | 0x8]; // bits 6-7 of the clock_seq_hi_and_reserved to 01
    } else {
      s[i] = hexDigits[(Math.random() * 0x10) | 0];
    }
  }
  return s.join("");
}

const radio = ref(1);
const fit = ref('cover');

const handleUploadCoverSuccess = (response: any) => {
  console.log('handleUploadCoverSuccess', response);
  useArticleStore().possibleCovers.selectedCover = response.data.imageUrl;
};

const mediaStore = useMediaStore();

const loading = reactive({
  materialListCard: false
});

/**
 * 将数组转换为二维数组
 *
 * @param arr 数组
 * @param n 每一行有多少个元素
 */
function to2DArray(arr: any[], n: number): any[][] {
  if (!Array.isArray(arr) || !Number.isInteger(n) || n <= 0) {
    throw new Error('Invalid arguments. arr must be an array of numbers and n must be a positive integer.');
  }

  let twoDArray: any[][] = [];
  let chunk: any[];

  while (arr.length > 0) {
    chunk = arr.slice(0, n); // 取出前 n 个元素
    arr = arr.slice(n); // 移除前 n 个元素
    twoDArray.push(chunk); // 将 chunk 添加到二维数组中
  }
  return twoDArray;
}

const pageParam = reactive({
  // 当前页码
  pageNum: 1,
  // 每页显示条目个数
  pageSize: 20,
})

// 监听分页参数变化
watch(pageParam, () => {
  getMediaList()
}, {
  deep: true,
  immediate: true
})
// 分页组相关配置
const paginationSettings = reactive({
  // 分页组件是否使用小型分页样式
  small: true,
  // 分页组件是否显示背景色
  background: false,
  // 分页组件禁用状态
  disabled: false,
  pageSizes: [5, 10, 20, 30, 40, 50, 100]
})

/**
 * 获取媒体图片列表
 */
function getMediaList() {
  if (!useSettingStore().previewing) mediaStore.clearMaterialInfo()
  loading.materialListCard = true
  mediaStore.pageQuery({pageNum: pageParam.pageNum, pageSize: pageParam.pageSize})
      .then(() => {
        mediaStore.materialInfo.mediaImageList.forEach(item => {
          item.showButton = false
        })
      }).finally(() => {
    loading.materialListCard = false
  })
}
</script>


<template>
  <el-dialog
      v-model="centerDialogVisible"
      title="添加图片"
      width="700px"
      align-center
      style=""
  >
    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
      <el-tab-pane label="本地文件" name="first">
        <el-upload
            class="upload-demo"
            drag
            :action="'http://localhost:5603/api/article/articleImg/upload'"
            :headers="{'token': useUserStore().userState.token}"
            :on-success="handleUploadSuccess"
            name="articleImage"
            :on-error="uploadError"
            :show-file-list="false"
            :data="new SaveArticleImgReqData(
                useArticleStore().articleInfo.id,
                useArticleStore().articleInfo.tempId,
                ArticleTypeEnum.CONTENT,
                null,null,null
                )"
        >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
          <div class="el-upload__tip" slot="tip" type="success">哈哈哈哈哈哈哈哈哈</div>
        </el-upload>
      </el-tab-pane>
      <el-tab-pane label="素材" name="second">
        <el-empty description="什么也没有诶~"
                  v-if="mediaStore.materialInfo.mediaImageList.length === 0 && !loading.materialListCard"
                  style="margin: auto;">
          <el-button @click="getMediaList()" :icon="RefreshRight" type="info" circle/>
        </el-empty>
        <el-scrollbar
            v-else
            v-loading="loading.materialListCard"
            :element-loading-spinner="useSettingStore().svg"
            element-loading-background="#ffffff"
            style="width: 100%; margin: auto;"
        >
          <div v-for="(oneDArr, index) in to2DArray(mediaStore.materialInfo.mediaImageList,6)"
               :key="index" style="display: flex;">
            <div v-for="item in oneDArr" :key="item.id"
                 style="display: inline-block; border: 1px solid #f5f5f5; padding: 10px; margin: 20px;">
              <div style="position: relative" class="img" @mouseover="item.showButton = true;"
                   @mouseleave="item.showButton = false">
                <el-image :src="item.url" fit="cover" style="width: 50px; height: 50px;"
                          @click="()=>{
                            if(insertImage) { insertImage(item.url, item.imageName, item.url);}
                            centerDialogVisible = false;
                            saveArticleImageUrlReq(item.url, '');
                          }"/>
              </div>
              <div
                  style="text-align: center; margin-top: 5px;font-weight: bolder; font-family: 宋体,'Microsoft YaHei', serif; font-size: 12px">
                {{ item.imageName }}
              </div>
            </div>
            <div style="display: inline-block; border: 1px; padding: 10px; margin: 20px; width: 100px; height: 100px;"
                 v-for="item in 6 - oneDArr.length"
                 :key="item">
            </div>
          </div>
        </el-scrollbar>
        <div v-show="mediaStore.materialInfo.total > 0 && !loading.materialListCard"
             style="display: flex; justify-content: center; margin-top: 20px;">
          <el-pagination
              v-model:current-page="pageParam.pageNum"
              v-model:page-size="pageParam.pageSize"
              :page-sizes="paginationSettings.pageSizes"
              :small="paginationSettings.small"
              :disabled="paginationSettings.disabled"
              :background="paginationSettings.background"
              layout="total, sizes, prev, pager, next, jumper"
              :total="mediaStore.materialInfo.total"
              @size-change=""
              @current-change=""
          />
        </div>
      </el-tab-pane>
    </el-tabs>
  </el-dialog>
  <el-scrollbar style="">
    <el-row>
      <el-col :span="4">
        <h2 style="margin: 20px auto; text-align: center; font-weight: bold; font-size: 20px; font-family: 华文宋体,sans-serif">
          封面</h2>
        <div style="margin-left: 10px">
          <el-radio-group v-model="radio" button-style="outline" class="button-radio-group" style="">
            <table>
              <tr>
                <td>
                  <el-radio :value="1">上传封面</el-radio>
                </td>
                <td>
                  <el-radio :value="2">内容封面</el-radio>
                </td>
              </tr>
              <tr>
                <td>
                  <el-radio :value="3">从素材库中选择</el-radio>
                </td>
                <td>
                  <el-radio :value="4">无封面</el-radio>
                </td>
              </tr>
            </table>
          </el-radio-group>
        </div>
        <el-upload
            class="upload-cover"
            drag
            :action="'http://localhost:5603/api/article/articleImg/upload'"
            :headers="{'token': useUserStore().userState.token}"
            :on-success="handleUploadCoverSuccess"
            name="articleImage"
            :on-error="uploadError"
            :show-file-list="false"
            v-if="radio === 1"
            :data="new SaveArticleImgReqData(
                useArticleStore().articleInfo.id,
                useArticleStore().articleInfo.tempId,
                ArticleTypeEnum.COVER,
                null,null,null
                )"
        >
          <el-image :src="useArticleStore().possibleCovers.selectedCover" :fit="fit">
            <template #error>
              <div class="image-slot">
                <el-icon size="20">
                  <Warning/>
                </el-icon>
              </div>
            </template>
            <template #placeholder>
              <div class="image-slot">
                <el-icon size="20">
                  <Plus/>
                </el-icon>
              </div>
            </template>
          </el-image>
        </el-upload>
        <div v-if="radio===2" style="margin: 0 auto; width: 80%">

        </div>
      </el-col>
      <el-col :span="16" style="padding: 20px 10px; overflow: hidden;">
        <el-row>
          <el-col :span="24">
            <el-input
                v-model="useArticleStore().articleInfo.title"
                type="text"
                placeholder="请输入标题"
                style="width: 100%; margin-bottom: 20px; font-size: 20px; font-weight: bold;"
            />
          </el-col>
        </el-row>
        <el-scrollbar height="">
          <el-row>
            <div style="border: 1px solid #ccc; z-index: 999">
              <Toolbar
                  style="border-bottom: 1px solid #ccc"
                  :editor="editorRef"
                  :defaultConfig="toolbarConfig"
                  :mode="mode"
              />
              <Editor
                  style="height: 25em; overflow-y: hidden;"
                  v-model="useArticleStore().articleInfo.content"
                  :defaultConfig="editorConfig"
                  :mode="mode"
                  @onCreated="handleCreated"
                  @onChange="handleChange"
              />
            </div>
          </el-row>
          <el-row
              class="button-container"
              justify="end"
              style="margin-top: 20px; padding: 0 20px;"
          >
            <el-button
                v-if="useArticleStore().articleInfo.status === '草稿' || useArticleStore().articleInfo.status === '' || useArticleStore().articleInfo.status === null"
                class="custom-button draft-btn"
                @click="() => saveArticle(1)"
            >
              <i class="el-icon-save"></i> 保存草稿
            </el-button>
            <el-button
                type="primary"
                plain
                class="custom-button submit-btn"
                @click="() => saveArticle(2)"
            >
              提交审核 <i class="el-icon-arrow-right"></i>
            </el-button>
          </el-row>
        </el-scrollbar>
      </el-col>
      <el-col :span="4"/>
    </el-row>
  </el-scrollbar>
</template>

<style scoped lang="scss">
.article-tabs > .el-tabs__content {
  padding: 32px;
  color: #6b778c;
  font-size: 32px;
  font-weight: 600;
}

.button-radio-group {
  display: flex;
  gap: 8px;
  max-width: 100%; /* 限制最大宽度，配合flex-shrink自适应 */
}

.el-radio-button {
  flex-shrink: 1; /* 按钮样式的radio会变为el-radio-button类 */
  min-width: 80px; /* 最小宽度 */
}

.upload-cover {
  margin: auto;
  width: 150px;
  height: 150px;
}

.button-radio-group {
  margin: 10px 0;
}

.button-radio-group table td {
  padding: 10px;
}

.button-radio-group .el-radio {
  margin: 0;
}
</style>
